package com.lzb.compressmaster.utils;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 批量解压工具类
 * 支持ZIP、7Z、TAR、TAR.GZ、TAR.BZ2、TAR.XZ等多种格式的批量解压
 */
public class BatchDecompressUtil {

    private static final String TAG = "BatchDecompressUtil";
    private static final int BUFFER_SIZE = 8192;

    public enum ArchiveType {
        ZIP, SEVEN_Z, TAR, TAR_GZ, TAR_BZ2, TAR_XZ, GZ, BZ2, XZ, UNKNOWN
    }

    public interface DecompressCallback {
        void onProgress(int current, int total, String currentFile);
        void onSuccess(List<String> extractedFiles);
        void onError(String error);
    }

    /**
     * 批量解压文件
     */
    public static void batchDecompress(Context context, List<String> archivePaths, 
                                     String outputDir, DecompressCallback callback) {
        new Thread(() -> {
            try {
                List<String> allExtractedFiles = new ArrayList<>();
                int total = archivePaths.size();
                
                for (int i = 0; i < total; i++) {
                    String archivePath = archivePaths.get(i);
                    String archiveName = new File(archivePath).getName();
                    
                    // 更新进度
                    int current = i + 1;
                    new Handler(Looper.getMainLooper()).post(() -> 
                        callback.onProgress(current, total, archiveName)
                    );
                    
                    // 解压单个文件
                    List<String> extractedFiles = decompressArchive(context, archivePath, outputDir);
                    allExtractedFiles.addAll(extractedFiles);
                }
                
                // 全部完成
                new Handler(Looper.getMainLooper()).post(() -> 
                    callback.onSuccess(allExtractedFiles)
                );
                
            } catch (Exception e) {
                Log.e(TAG, "批量解压失败", e);
                new Handler(Looper.getMainLooper()).post(() -> 
                    callback.onError(e.getMessage())
                );
            }
        }).start();
    }

    /**
     * 解压单个压缩文件
     */
    public static List<String> decompressArchive(Context context, String archivePath, 
                                               String outputDir) throws IOException {
        File archiveFile = new File(archivePath);
        if (!archiveFile.exists()) {
            throw new IOException("压缩文件不存在: " + archivePath);
        }

        ArchiveType type = detectArchiveType(archivePath);
        if (type == ArchiveType.UNKNOWN) {
            throw new IOException("不支持的压缩格式: " + archivePath);
        }

        // 创建与压缩包同名的文件夹
        String archiveName = archiveFile.getName();
        String folderName = getFolderNameWithoutExtension(archiveName, type);
        File outputDirectory = new File(outputDir, folderName);
        if (!outputDirectory.exists()) {
            outputDirectory.mkdirs();
        }

        List<String> extractedFiles = new ArrayList<>();

        switch (type) {
            case ZIP:
                extractedFiles.addAll(decompressZip(archivePath, outputDirectory.getAbsolutePath()));
                break;
            case SEVEN_Z:
                extractedFiles.addAll(decompress7z(archivePath, outputDirectory.getAbsolutePath()));
                break;
            case TAR:
                extractedFiles.addAll(decompressTar(archivePath, outputDirectory.getAbsolutePath()));
                break;
            case TAR_GZ:
                extractedFiles.addAll(decompressTarGz(archivePath, outputDirectory.getAbsolutePath()));
                break;
            case TAR_BZ2:
                extractedFiles.addAll(decompressTarBz2(archivePath, outputDirectory.getAbsolutePath()));
                break;
            case TAR_XZ:
                extractedFiles.addAll(decompressTarXz(archivePath, outputDirectory.getAbsolutePath()));
                break;
            case GZ:
                extractedFiles.addAll(decompressGz(archivePath, outputDirectory.getAbsolutePath()));
                break;
            case BZ2:
                extractedFiles.addAll(decompressBz2(archivePath, outputDirectory.getAbsolutePath()));
                break;
            case XZ:
                extractedFiles.addAll(decompressXz(archivePath, outputDirectory.getAbsolutePath()));
                break;
        }

        return extractedFiles;
    }

    /**
     * 获取不带扩展名的文件夹名称
     */
    private static String getFolderNameWithoutExtension(String archiveName, ArchiveType type) {
        switch (type) {
            case TAR_GZ:
                return archiveName.replaceAll("\\.tar\\.gz$", "").replaceAll("\\.tgz$", "");
            case TAR_BZ2:
                return archiveName.replaceAll("\\.tar\\.bz2$", "");
            case TAR_XZ:
                return archiveName.replaceAll("\\.tar\\.xz$", "");
            case ZIP:
                return archiveName.replaceAll("\\.zip$", "");
            case SEVEN_Z:
                return archiveName.replaceAll("\\.7z$", "");
            case TAR:
                return archiveName.replaceAll("\\.tar$", "");
            case GZ:
                return archiveName.replaceAll("\\.gz$", "");
            case BZ2:
                return archiveName.replaceAll("\\.bz2$", "");
            case XZ:
                return archiveName.replaceAll("\\.xz$", "");
            default:
                // 如果没有匹配到扩展名，返回原文件名
                int lastDotIndex = archiveName.lastIndexOf('.');
                return lastDotIndex > 0 ? archiveName.substring(0, lastDotIndex) : archiveName;
        }
    }

    /**
     * 检测压缩文件类型
     */
    private static ArchiveType detectArchiveType(String filePath) {
        String path = filePath.toLowerCase();
        
        if (path.endsWith(".zip")) {
            return ArchiveType.ZIP;
        } else if (path.endsWith(".7z")) {
            return ArchiveType.SEVEN_Z;
        } else if (path.endsWith(".tar")) {
            return ArchiveType.TAR;
        } else if (path.endsWith(".tar.gz") || path.endsWith(".tgz")) {
            return ArchiveType.TAR_GZ;
        } else if (path.endsWith(".tar.bz2")) {
            return ArchiveType.TAR_BZ2;
        } else if (path.endsWith(".tar.xz")) {
            return ArchiveType.TAR_XZ;
        } else if (path.endsWith(".gz")) {
            return ArchiveType.GZ;
        } else if (path.endsWith(".bz2")) {
            return ArchiveType.BZ2;
        } else if (path.endsWith(".xz")) {
            return ArchiveType.XZ;
        }
        
        return ArchiveType.UNKNOWN;
    }

    /**
     * 解压ZIP文件
     */
    private static List<String> decompressZip(String zipPath, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        try (ZipArchiveInputStream zis = new ZipArchiveInputStream(
                new BufferedInputStream(new FileInputStream(zipPath)))) {
            
            ZipArchiveEntry entry;
            while ((entry = zis.getNextZipEntry()) != null) {
                String fileName = entry.getName();
                File outputFile = new File(outputDir, fileName);
                
                if (entry.isDirectory()) {
                    outputFile.mkdirs();
                } else {
                    // 确保父目录存在
                    File parentDir = outputFile.getParentFile();
                    if (parentDir != null && !parentDir.exists()) {
                        parentDir.mkdirs();
                    }
                    
                    // 解压文件
                    try (BufferedOutputStream bos = new BufferedOutputStream(
                            new FileOutputStream(outputFile))) {
                        byte[] buffer = new byte[BUFFER_SIZE];
                        int len;
                        while ((len = zis.read(buffer)) > 0) {
                            bos.write(buffer, 0, len);
                        }
                    }
                    extractedFiles.add(outputFile.getAbsolutePath());
                }
            }
        }
        
        return extractedFiles;
    }

    /**
     * 解压7Z文件
     */
    private static List<String> decompress7z(String sevenZPath, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        try (SevenZFile sevenZFile = new SevenZFile(new File(sevenZPath))) {
            SevenZArchiveEntry entry;
            while ((entry = sevenZFile.getNextEntry()) != null) {
                String fileName = entry.getName();
                File outputFile = new File(outputDir, fileName);
                
                if (entry.isDirectory()) {
                    outputFile.mkdirs();
                } else {
                    // 确保父目录存在
                    File parentDir = outputFile.getParentFile();
                    if (parentDir != null && !parentDir.exists()) {
                        parentDir.mkdirs();
                    }
                    
                    // 解压文件
                    try (BufferedOutputStream bos = new BufferedOutputStream(
                            new FileOutputStream(outputFile))) {
                        byte[] buffer = new byte[BUFFER_SIZE];
                        int len;
                        while ((len = sevenZFile.read(buffer)) > 0) {
                            bos.write(buffer, 0, len);
                        }
                    }
                    extractedFiles.add(outputFile.getAbsolutePath());
                }
            }
        }
        
        return extractedFiles;
    }

    /**
     * 解压TAR文件
     */
    private static List<String> decompressTar(String tarPath, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        try (TarArchiveInputStream tis = new TarArchiveInputStream(
                new BufferedInputStream(new FileInputStream(tarPath)))) {
            
            TarArchiveEntry entry;
            while ((entry = tis.getNextTarEntry()) != null) {
                String fileName = entry.getName();
                File outputFile = new File(outputDir, fileName);
                
                if (entry.isDirectory()) {
                    outputFile.mkdirs();
                } else {
                    // 确保父目录存在
                    File parentDir = outputFile.getParentFile();
                    if (parentDir != null && !parentDir.exists()) {
                        parentDir.mkdirs();
                    }
                    
                    // 解压文件
                    try (BufferedOutputStream bos = new BufferedOutputStream(
                            new FileOutputStream(outputFile))) {
                        byte[] buffer = new byte[BUFFER_SIZE];
                        int len;
                        while ((len = tis.read(buffer)) > 0) {
                            bos.write(buffer, 0, len);
                        }
                    }
                    extractedFiles.add(outputFile.getAbsolutePath());
                }
            }
        }
        
        return extractedFiles;
    }

    /**
     * 解压TAR.GZ文件
     */
    private static List<String> decompressTarGz(String tarGzPath, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        try (TarArchiveInputStream tis = new TarArchiveInputStream(
                new GzipCompressorInputStream(new FileInputStream(tarGzPath)))) {
            
            TarArchiveEntry entry;
            while ((entry = tis.getNextTarEntry()) != null) {
                String fileName = entry.getName();
                File outputFile = new File(outputDir, fileName);
                
                if (entry.isDirectory()) {
                    outputFile.mkdirs();
                } else {
                    File parentDir = outputFile.getParentFile();
                    if (parentDir != null && !parentDir.exists()) {
                        parentDir.mkdirs();
                    }
                    
                    try (BufferedOutputStream bos = new BufferedOutputStream(
                            new FileOutputStream(outputFile))) {
                        byte[] buffer = new byte[BUFFER_SIZE];
                        int len;
                        while ((len = tis.read(buffer)) > 0) {
                            bos.write(buffer, 0, len);
                        }
                    }
                    extractedFiles.add(outputFile.getAbsolutePath());
                }
            }
        }
        
        return extractedFiles;
    }

    /**
     * 解压TAR.BZ2文件
     */
    private static List<String> decompressTarBz2(String tarBz2Path, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        try (TarArchiveInputStream tis = new TarArchiveInputStream(
                new BZip2CompressorInputStream(new FileInputStream(tarBz2Path)))) {
            
            TarArchiveEntry entry;
            while ((entry = tis.getNextTarEntry()) != null) {
                String fileName = entry.getName();
                File outputFile = new File(outputDir, fileName);
                
                if (entry.isDirectory()) {
                    outputFile.mkdirs();
                } else {
                    File parentDir = outputFile.getParentFile();
                    if (parentDir != null && !parentDir.exists()) {
                        parentDir.mkdirs();
                    }
                    
                    try (BufferedOutputStream bos = new BufferedOutputStream(
                            new FileOutputStream(outputFile))) {
                        byte[] buffer = new byte[BUFFER_SIZE];
                        int len;
                        while ((len = tis.read(buffer)) > 0) {
                            bos.write(buffer, 0, len);
                        }
                    }
                    extractedFiles.add(outputFile.getAbsolutePath());
                }
            }
        }
        
        return extractedFiles;
    }

    /**
     * 解压TAR.XZ文件
     */
    private static List<String> decompressTarXz(String tarXzPath, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        try (TarArchiveInputStream tis = new TarArchiveInputStream(
                new XZCompressorInputStream(new FileInputStream(tarXzPath)))) {
            
            TarArchiveEntry entry;
            while ((entry = tis.getNextTarEntry()) != null) {
                String fileName = entry.getName();
                File outputFile = new File(outputDir, fileName);
                
                if (entry.isDirectory()) {
                    outputFile.mkdirs();
                } else {
                    File parentDir = outputFile.getParentFile();
                    if (parentDir != null && !parentDir.exists()) {
                        parentDir.mkdirs();
                    }
                    
                    try (BufferedOutputStream bos = new BufferedOutputStream(
                            new FileOutputStream(outputFile))) {
                        byte[] buffer = new byte[BUFFER_SIZE];
                        int len;
                        while ((len = tis.read(buffer)) > 0) {
                            bos.write(buffer, 0, len);
                        }
                    }
                    extractedFiles.add(outputFile.getAbsolutePath());
                }
            }
        }
        
        return extractedFiles;
    }

    /**
     * 解压GZ文件
     */
    private static List<String> decompressGz(String gzPath, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        File gzFile = new File(gzPath);
        String fileName = gzFile.getName().replace(".gz", "");
        File outputFile = new File(outputDir, fileName);
        
        try (GzipCompressorInputStream gis = new GzipCompressorInputStream(
                new FileInputStream(gzFile));
             BufferedOutputStream bos = new BufferedOutputStream(
                     new FileOutputStream(outputFile))) {
            
            byte[] buffer = new byte[BUFFER_SIZE];
            int len;
            while ((len = gis.read(buffer)) > 0) {
                bos.write(buffer, 0, len);
            }
            
            extractedFiles.add(outputFile.getAbsolutePath());
        }
        
        return extractedFiles;
    }

    /**
     * 解压BZ2文件
     */
    private static List<String> decompressBz2(String bz2Path, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        File bz2File = new File(bz2Path);
        String fileName = bz2File.getName().replace(".bz2", "");
        File outputFile = new File(outputDir, fileName);
        
        try (BZip2CompressorInputStream bis = new BZip2CompressorInputStream(
                new FileInputStream(bz2File));
             BufferedOutputStream bos = new BufferedOutputStream(
                     new FileOutputStream(outputFile))) {
            
            byte[] buffer = new byte[BUFFER_SIZE];
            int len;
            while ((len = bis.read(buffer)) > 0) {
                bos.write(buffer, 0, len);
            }
            
            extractedFiles.add(outputFile.getAbsolutePath());
        }
        
        return extractedFiles;
    }

    /**
     * 解压XZ文件
     */
    private static List<String> decompressXz(String xzPath, String outputDir) throws IOException {
        List<String> extractedFiles = new ArrayList<>();
        
        File xzFile = new File(xzPath);
        String fileName = xzFile.getName().replace(".xz", "");
        File outputFile = new File(outputDir, fileName);
        
        try (XZCompressorInputStream xis = new XZCompressorInputStream(
                new FileInputStream(xzFile));
             BufferedOutputStream bos = new BufferedOutputStream(
                     new FileOutputStream(outputFile))) {
            
            byte[] buffer = new byte[BUFFER_SIZE];
            int len;
            while ((len = xis.read(buffer)) > 0) {
                bos.write(buffer, 0, len);
            }
            
            extractedFiles.add(outputFile.getAbsolutePath());
        }
        
        return extractedFiles;
    }
}